home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / DimText 2.0 / Dim_text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-14  |  8.9 KB  |  354 lines  |  [TEXT/KAHL]

  1. #include <Memory.h>
  2. #include <Palettes.h>
  3. #include <Dialogs.h>
  4. #include <GestaltEqu.h>
  5. #include "Dim_text.h"
  6.  
  7. static pascal void Dim_text_proc( short byteCnt, Ptr textAddr,
  8.         Point numerPt, Point denomPt );
  9. static void Gray_frame_rect( Rect *bounds );
  10. static pascal void Gray_frame_draw_proc( short depth, short dev_flags,
  11.     GDHandle dev, Rect *bounds );
  12.  
  13. /*    ---------------------------------------------------------------------
  14.     Dim_text            This is a group of routines for dimming text
  15.                         items in dialogs.  As is, it assumes that you are
  16.                         not using the dialog's refCon for anything else,
  17.                         and that you are not using the QuickDraw
  18.                         bottlenecks for anything else.
  19.     
  20.     This code can be used freely.  I ask that you tell me about any
  21.     improvements that you think of.
  22.     
  23.     James W. Walker        May 4, 1994
  24.     JWWalker@AOL.com
  25.     76367.2271@compuserve.com
  26.     ---------------------------------------------------------------------
  27. */
  28.  
  29. #define        SYSTEM_6_COMPATIBLE        1
  30.  
  31. typedef struct Dim_list_el {
  32.     short                item_num;
  33.     struct Dim_list_el    *next;
  34.     Rect                bounds;
  35.     Boolean                editable;
  36. } Dim_list_el;
  37.  
  38. typedef struct {
  39.     Dim_list_el    *dim_list;
  40.     QDTextUPP    Old_text_proc;
  41. #if SYSTEM_6_COMPATIBLE
  42.     Boolean        has_gray_text;
  43. #endif
  44. } Dim_data;
  45.  
  46.  
  47. /*    ---------------------------------------------------------------------
  48.     Get_dim_data        Macro to get the list head.
  49.                         Just used to encapsulate the use of the refCon,
  50.                         so that if you need to store the list head
  51.                         somewhere else you will only need to change this
  52.                         and Init_dimmer.
  53.     ---------------------------------------------------------------------
  54. */
  55. #define    Get_dim_data( dp )        ((Dim_data *) ((WindowPeek)dp)->refCon)
  56.  
  57.  
  58. /*    ---------------------------------------------------------------------
  59.     Init_dimmer        Set up a dialog for dimming text.  Call it once, soon
  60.                     after creating the dialog.
  61.     ---------------------------------------------------------------------
  62. */
  63. void Init_dimmer( DialogPtr dp )
  64. {
  65.     Dim_data    *dim_head;
  66.     QDProcs        *qd_procs;
  67.     long        val;
  68.     
  69.     dim_head = (Dim_data *) NewPtrClear( sizeof(Dim_data) );
  70.     if (dim_head)
  71.     {
  72.         // Store the pointer where we can find it later
  73.         ((WindowPeek)dp)->refCon = (long) dim_head;
  74.         
  75.         // Patch the QuickDraw bottleneck for text
  76.         if ( (dp->portBits.rowBytes & 0x8000) == 0 )    // B&W port
  77.         {
  78.             qd_procs = (QDProcs *) NewPtrSysClear( sizeof(QDProcs) );
  79.             SetStdProcs( qd_procs );
  80.         }
  81.         else    // color port
  82.         {
  83.             qd_procs = (QDProcs *) NewPtrSysClear( sizeof(CQDProcs) );
  84.             SetStdCProcs( (CQDProcs *) qd_procs );
  85.         }
  86.         dim_head->Old_text_proc = qd_procs->textProc;
  87.         qd_procs->textProc = NewQDTextProc( Dim_text_proc );
  88.         dp->grafProcs = qd_procs;
  89.         
  90. #if SYSTEM_6_COMPATIBLE
  91.         // Which System 7 features are available?
  92.         dim_head->has_gray_text =
  93.             (Gestalt( gestaltQuickdrawFeatures, &val ) == noErr)
  94.             && ( (val & (1L << gestaltHasGrayishTextOr)) != 0 );
  95. #endif        
  96.  
  97.     } // end if (dim_head)
  98. }
  99.  
  100.  
  101. /*    ---------------------------------------------------------------------
  102.     Dispose_dimmer        Called once after you are through with a dialog.
  103.     ---------------------------------------------------------------------
  104. */
  105. void Dispose_dimmer( DialogPtr dp )
  106. {
  107.     Dim_data    *dim_head;
  108.     Dim_list_el    *this_el, *next;
  109.     
  110.     dim_head = Get_dim_data(dp);
  111.     if (dim_head)
  112.     {
  113.         this_el = dim_head->dim_list;
  114.         while (this_el != NULL)
  115.         {
  116.             EraseRect( &this_el->bounds );
  117.             next = this_el->next;
  118.             DisposePtr( (Ptr) this_el );
  119.             this_el = next;
  120.         }
  121.         
  122.         DisposePtr( (Ptr) dim_head );
  123.     }
  124.  
  125.     if (dp->grafProcs)
  126.     {
  127.         DisposeRoutineDescriptor( qd_procs->textProc );
  128.         DisposePtr( (Ptr) dp->grafProcs );
  129.     }
  130.     dp->grafProcs = NULL;
  131. }
  132.  
  133. /*    ---------------------------------------------------------------------
  134.     Dim_text        Set the dimming state of a text item.
  135.     ---------------------------------------------------------------------
  136. */
  137. void Dim_text( DialogPtr dp, short item, Boolean dim )
  138. {
  139.     Dim_data    *dim_head;
  140.     Dim_list_el    *dimmable, *predecessor;
  141.     Rect        iRect;
  142.     Handle        iHandle;
  143.     short        iType;
  144.     short        disable_flag;
  145.     
  146.     dim_head = Get_dim_data(dp);
  147.     if (dim_head != NULL)
  148.     {
  149.         GetDItem( dp, item, &iType, &iHandle, &iRect );
  150.         disable_flag = iType & itemDisable;
  151.  
  152.         // Try to find the right item number in the list.
  153.         dimmable = dim_head->dim_list;
  154.         while ( (dimmable != NULL) && (dimmable->item_num != item) )
  155.         {
  156.             dimmable = dimmable->next;
  157.         }
  158.  
  159.         if ( (dimmable == NULL) && dim )    // dim it
  160.         {
  161.             dimmable = (Dim_list_el *) 
  162.                 NewPtrClear( sizeof(Dim_list_el) );
  163.             if (dimmable)
  164.             {
  165.                 dimmable->next = dim_head->dim_list;
  166.                 dim_head->dim_list = dimmable;
  167.                 dimmable->item_num = item;
  168.                 dimmable->editable = (iType & editText) != 0;
  169.                 dimmable->bounds = iRect;
  170.                 if (dimmable->editable)
  171.                 {
  172.                     InsetRect( &dimmable->bounds, -3, -3 );
  173.                     /*
  174.                         To dim an editable text item, we need to turn it
  175.                         into a static text item, and also take some care
  176.                         that it is not showing the insertion point or a
  177.                         selection range.
  178.                     */
  179.                     TEDeactivate( ((DialogPeek) dp)->textH );
  180.                     if (item == ((DialogPeek) dp)->editField + 1 )
  181.                     {
  182.                         SelIText( dp, item, 0, 0 );
  183.                         ((DialogPeek) dp)->editField = -1;
  184.                     }
  185.                     SetDItem( dp, item, statText | disable_flag,
  186.                         iHandle, &iRect );
  187.                     ((DialogPeek) dp)->editField = -1;
  188.                     TEActivate( ((DialogPeek) dp)->textH );
  189.                     InvalRect( &dimmable->bounds );
  190.                 }
  191.                 else
  192.                 {
  193.                     InvalRect( &iRect );
  194.                 }
  195.             }
  196.         }
  197.         else if ( (dimmable != NULL) && !dim )    // undim it
  198.         {
  199.             // Remove it from the list
  200.             if (dim_head->dim_list == dimmable)
  201.             {
  202.                 dim_head->dim_list = dimmable->next;
  203.             }
  204.             else
  205.             {
  206.                 predecessor = dim_head->dim_list;
  207.                 while (predecessor->next != dimmable)
  208.                 {
  209.                     predecessor = predecessor->next;
  210.                 }
  211.                 predecessor->next = dimmable->next;
  212.             }
  213.             
  214.             if (dimmable->editable)
  215.             {
  216.                 SetDItem( dp, item, editText | disable_flag,
  217.                     iHandle, &iRect );
  218.                 SelIText( dp, item, 0, 0 );
  219.                 EraseRect( &iRect );
  220.                 FrameRect( &dimmable->bounds );
  221.                 TEUpdate( &iRect, ((DialogPeek) dp)->textH );
  222.             }
  223.             else
  224.             {
  225.                 InvalRect( &iRect );
  226.             }
  227.             
  228.             // Delete the list element
  229.             DisposePtr( (Ptr) dimmable );
  230.         }
  231.     }
  232. }
  233.  
  234.  
  235. /*    ---------------------------------------------------------------------
  236.     Dim_text_proc            The QuickDraw bottleneck routine that does
  237.                             the actual dimming, and also draws the frame
  238.                             around dimmed editable text.
  239.     ---------------------------------------------------------------------
  240. */
  241. static pascal void Dim_text_proc( short byteCnt, Ptr textAddr,
  242.         Point numerPt, Point denomPt )
  243. {
  244.     short            item_num;
  245.     DialogPtr        dp;
  246.     Dim_list_el        *dimmable;
  247.     Dim_data        *dim_head;
  248.     Rect            gray_rect;
  249.     PenState        save_pen;
  250.     
  251.     GetPort( &dp );
  252.     dim_head = Get_dim_data( dp );
  253.     item_num = FindDItem( dp, dp->pnLoc ) + 1;
  254.     dimmable = dim_head->dim_list;
  255.     while ( (dimmable != NULL) && (dimmable->item_num != item_num) )
  256.     {
  257.         dimmable = dimmable->next;
  258.     }
  259.     if ( dimmable != NULL )
  260.     {
  261. #if SYSTEM_6_COMPATIBLE
  262.         if (dim_head->has_gray_text)
  263. #endif
  264.         {
  265.             TextMode( grayishTextOr );
  266.         }
  267.         if (dimmable->editable)
  268.         {
  269.             Gray_frame_rect( &dimmable->bounds );
  270.         }
  271.     }
  272.  
  273.     CallQDTextProc( dim_head->Old_text_proc, byteCnt, textAddr,
  274.         numerPt, denomPt );
  275.  
  276. #if SYSTEM_6_COMPATIBLE    
  277.     if ( !dim_head->has_gray_text && (dimmable != NULL) )
  278.     {
  279.         gray_rect = dimmable->bounds;
  280.         InsetRect( &gray_rect, 1, 1 );
  281.         GetPenState( &save_pen );
  282.         PenMode( patBic );
  283.         /*
  284.             The reason I used a string literal rather than the QuickDraw
  285.             global gray is so that it can be used in a code resource
  286.             without problems.
  287.         */
  288.         PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55" );
  289.         PaintRect( &gray_rect );
  290.         SetPenState( &save_pen );
  291.     }
  292. #endif
  293. }
  294.  
  295. /*    ---------------------------------------------------------------------
  296.     Gray_frame_draw_proc        DeviceLoop drawing procedure called
  297.                                 by Gray_frame_rect.
  298.     ---------------------------------------------------------------------
  299. */
  300. static pascal void Gray_frame_draw_proc( short depth, short dev_flags,
  301.     GDHandle dev, Rect *bounds )
  302. {
  303.     RGBColor    fore_color, back_color, gray_color;
  304.     
  305.     if (depth > 1)
  306.     {
  307.         GetForeColor( &fore_color );
  308.         GetBackColor( &back_color );
  309.         gray_color = fore_color;
  310.         GetGray( dev, &back_color, &gray_color );
  311.         RGBForeColor( &gray_color );
  312.     }
  313.     else
  314.     {
  315.         PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55" );
  316.     }
  317.     
  318.     FrameRect( bounds );
  319.     
  320.     if (depth > 1)
  321.     {
  322.         RGBForeColor( &fore_color );
  323.     }
  324.     else
  325.     {
  326.         PenNormal();
  327.     }
  328. }
  329.  
  330. /*    ---------------------------------------------------------------------
  331.     Gray_frame_rect                Draw a gray rectangle; true gray
  332.                                 if possible, dithered otherwise.
  333.     ---------------------------------------------------------------------
  334. */
  335. static void Gray_frame_rect( Rect *bounds )
  336. {
  337.     RgnHandle    save_clip, draw_rgn;
  338.     DeviceLoopDrawingUPP    Draw_UPP;
  339.     
  340.     PenNormal();
  341.     save_clip = NewRgn();
  342.     GetClip( save_clip );
  343.     draw_rgn = NewRgn();
  344.     RectRgn( draw_rgn, bounds );
  345.     SetClip( draw_rgn );
  346.     Draw_UPP = NewDeviceLoopDrawingProc( Gray_frame_draw_proc );
  347.     DeviceLoop( draw_rgn, Draw_UPP, (long) bounds, 0 );
  348.     DisposeRoutineDescriptor( Draw_UPP );
  349.     SetClip( save_clip );
  350.     DisposeRgn( draw_rgn );
  351.     DisposeRgn( save_clip );
  352.     PenNormal();
  353. }
  354.